package com.git.hui.yinshua.biz.order.service;

import com.git.hui.yinshua.api.model.CntDto;
import com.git.hui.yinshua.api.model.ExceptionUtil;
import com.git.hui.yinshua.api.model.ListRsp;
import com.git.hui.yinshua.api.model.ReqInfoContext;
import com.git.hui.yinshua.api.model.Status;
import com.git.hui.yinshua.api.model.order.OrderStatusEnum;
import com.git.hui.yinshua.api.model.order.OrderTypeEnum;
import com.git.hui.yinshua.api.model.order.PayStatusEnum;
import com.git.hui.yinshua.api.model.order.RefundStatusEnum;
import com.git.hui.yinshua.api.model.user.UserBo;
import com.git.hui.yinshua.biz.order.dao.entity.OrderEntity;
import com.git.hui.yinshua.biz.order.dao.entity.PtOrderItemEntity;
import com.git.hui.yinshua.biz.order.dao.repository.OrderRepository;
import com.git.hui.yinshua.biz.order.service.convert.OrderConvert;
import com.git.hui.yinshua.biz.pay.service.PaymentService;
import com.git.hui.yinshua.biz.pay.service.RefundService;
import com.git.hui.yinshua.biz.rest.models.order.req.OrderQueryReq;
import com.git.hui.yinshua.biz.rest.models.order.rsp.OrderDto;
import com.git.hui.yinshua.biz.rest.models.order.rsp.PaymentDto;
import com.git.hui.yinshua.biz.rest.models.order.rsp.PtOrderDto;
import com.git.hui.yinshua.biz.rest.models.order.rsp.PtOrderMemberDto;
import com.git.hui.yinshua.biz.rest.models.order.rsp.RefundDto;
import com.git.hui.yinshua.biz.rest.models.user.res.UserInfoDto;
import com.git.hui.yinshua.biz.user.service.UserService;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author YiHui
 * @date 2024/6/20
 */
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private UserService userService;
    @Autowired
    private PtOrderService ptOrderService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private RefundService refundService;

    public OrderEntity lockOrder(Long orderId) {
        return orderRepository.querySimpleOrderForUpdate(orderId);
    }

    /**
     * 订单列表查询
     *
     * @param req
     * @return
     */
    public ListRsp<OrderDto> list(OrderQueryReq req) {
        if (StringUtils.isNotBlank(req.getPtOrder())) {
            // 根据拼团订单查询
            List<PtOrderItemEntity> list = ptOrderService.queryOrdersByPtOrderCode(req.getPtOrder());
            if (!CollectionUtils.isEmpty(list)) {
                req.setOrderIds(list.stream().map(PtOrderItemEntity::getRelatedOrderId).collect(Collectors.toList()));
            }
        }

        List<OrderEntity> orderEntities = orderRepository.listOrders(req);
        if (CollectionUtils.isEmpty(orderEntities)) {
            return ListRsp.newRsp(new ArrayList<>(), req.getPage(), req.getSize());
        }

        List<OrderDto> orders = OrderConvert.batchToOrders(orderEntities);

        Set<Long> allOrderIds = new HashSet<>();
        Set<Long> refundOrderIds = new HashSet<>();
        Set<Long> ptOrderIds = new HashSet<>();
        Set<Integer> userIds = new HashSet<>();
        for (OrderEntity entity : orderEntities) {
            allOrderIds.add(entity.getId());
            userIds.add(entity.getUid());
            if (Objects.equals(entity.getType(), OrderTypeEnum.PT.getType())) {
                ptOrderIds.add(entity.getId());
            }
            if (needQueryRefund(entity)) {
                refundOrderIds.add(entity.getId());
            }
        }
        // 用户补充用户信息
        List<UserInfoDto> userList = userService.listUserByUserIds(userIds);
        Map<Integer, UserInfoDto> userMap = userList.stream().collect(Collectors.toMap(UserBo::getUserId, s -> s));

        // 补充拼团单信息
        List<PtOrderDto> ptOrderList = ptOrderService.queryPtOrderByOrderIds(new ArrayList<>(ptOrderIds));
        Map<Long, PtOrderDto> ptMap = Maps.newHashMapWithExpectedSize(ptOrderIds.size());
        for (PtOrderDto dto : ptOrderList) {
            for (PtOrderMemberDto member : dto.getMembers()) {
                ptMap.put(member.getOrderId(), dto);
            }
        }

        // 补充支付单信息
        Map<Long, PaymentDto> payMap = paymentService.listSimplePaymentInfo(allOrderIds);

        // 补充退款单信息
        Map<Long, RefundDto> refundMap = refundService.listRefundInfo(refundOrderIds);

        orders.forEach(o -> {
            o.setUser(userMap.get(o.getUser().getUserId()));
            o.setPtOrder(ptMap.get(o.getOrderId()));
            o.setPayment(payMap.get(o.getOrderId()));
            o.setRefund(refundMap.get(o.getOrderId()));
        });

        return ListRsp.newRsp(orders, req.getPage(), req.getSize());
    }

    public ListRsp<OrderDto> listAndCount(OrderQueryReq req) {
        ListRsp<OrderDto> list = list(req);
        if (req.getPage() == 1) {
            list.setTotal(orderRepository.count(req));
        }
        return list;
    }

    public List<CntDto> listCntByStatus(OrderQueryReq req) {
        return orderRepository.countByStatus(req);
    }

    /**
     * 订单详情信息
     *
     * @param orderId 订单id
     * @return 订单实体
     */
    public OrderDto detail(Long orderId) {
        // 查询订单详情
        OrderEntity order = orderRepository.queryOrderDetail(orderId);
        OrderDto dto = OrderConvert.toOrder(order);

        // 补充用户信息
        dto.setUser(userService.getUserInfo(order.getUid()));

        // 补充支付详情
        PaymentDto payment = paymentService.getPaymentInfo(dto, null);
        if (payment != null) {
            dto.setPayment(payment);
        }

        if (needQueryRefund(order)) {
            // 补充退款信息
            RefundDto refund = refundService.getRefundInfo(orderId);
            dto.setRefund(refund);
        }
        return dto;
    }


    /**
     * 判断是否需要查询退款信息
     *
     * @param order 订单
     * @return true 表示发生了退款，应该查询对应的退款信息
     */
    private boolean needQueryRefund(OrderEntity order) {
        return Objects.equals(order.getPayStatus(), PayStatusEnum.REFUNDED.getStatus())
                || Objects.equals(order.getPayStatus(), PayStatusEnum.REFUNDING.getStatus());
    }

    /**
     * 订单发货
     *
     * @param orderId
     * @param company
     * @param code
     * @return
     */
    public boolean deliveryOrder(Long orderId, String company, String code) {
        return orderRepository.updateToReceive(orderId, company, code);
    }

    @Transactional
    public boolean deleteOrder(Long orderId) {
        OrderEntity order = orderRepository.querySimpleOrderForUpdate(orderId);
        Integer userId = ReqInfoContext.getReqInfo().getUserId();
        if (!order.getUid().equals(userId)) {
            throw ExceptionUtil.of(Status.StatusEnum.FORBID_ERROR_MIXED, "只能删除自己的订单");
        }

        if (Objects.equals(order.getOrderStatus(), OrderStatusEnum.CANCELED.getStatus())
                || Objects.equals(order.getOrderStatus(), OrderStatusEnum.REFUND.getStatus())) {
            // 只有这两个状态才支持删除
            return orderRepository.deleteOrder(orderId);
        }

        throw ExceptionUtil.of(Status.StatusEnum.BIZ_EXCEPTION, "只支持删除已取消/已退款的订单哦~");
    }

    /**
     * 下载了文件，更新为待发货
     *
     * @param orderId
     * @return
     */
    public boolean updateToDelivery(Long orderId) {
        OrderEntity order = orderRepository.querySimpleOrderForUpdate(orderId);
        // 只有待打印的订单，才允许将状态流转为待发货
        if (Objects.equals(order.getOrderStatus(), OrderStatusEnum.TO_PRINT.getStatus())) {
            return orderRepository.updateToExpress(orderId);
        }
        return false;
    }

    /**
     * 下载次数+1
     *
     * @param orderId
     * @return
     */
    public boolean updateDownCnt(Long orderId) {
        boolean ans = this.updateToDelivery(orderId);
        orderRepository.updateDownloadCnt(orderId);
        return ans;
    }

    /**
     * 订单支付结果回调
     *
     * @param orderId   订单id
     * @param payStatus true 表示支付成功
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean paymentCallback(Long orderId, PayStatusEnum payStatus, Long paySucceedTime) {
        OrderEntity order = orderRepository.querySimpleOrderForUpdate(orderId);
        // 1. 支付单支付未成功场景 ->
        if (payStatus != PayStatusEnum.SUCCEED) {
            // 订单支付状态更新为支付失败即可,对应的拼团订单信息不做任何更新
            orderRepository.updatePayStatus(orderId, payStatus, null, null);
            return true;
        }

        // 2. 支付单支付成功 ->
        // 2.1 非拼团订单，直接更新订单状态到待打印
        if (!OrderTypeEnum.PT.getType().equals(order.getType())) {
            // 将订单状态更新为已支付
            orderRepository.updatePayStatus(orderId, PayStatusEnum.SUCCEED, OrderStatusEnum.TO_PRINT, paySucceedTime);
            return true;
        }

        // 2.2 如果是拼团订单，则需要将对应的拼团状态更新为成功
        boolean ptSucceed = ptOrderService.ptOrderItemPaySucceed(order.getId());
        if (ptSucceed) {
            // 拼团成功
            orderRepository.updatePayStatus(orderId, PayStatusEnum.SUCCEED, OrderStatusEnum.TO_PRINT, paySucceedTime);
        } else {
            // 拼团未完成，更新订单状态为拼团中
            orderRepository.updatePayStatus(orderId, PayStatusEnum.SUCCEED, OrderStatusEnum.PT_ING, paySucceedTime);
        }
        return true;
    }


    /**
     * 订单退款信息回调
     *
     * @param orderId      订单id
     * @param refundStatus 退款单状态
     * @return true 表示执行成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean refundCallback(Long orderId, RefundStatusEnum refundStatus) {
        if (refundStatus == RefundStatusEnum.SUCCEED) {
            // 退款成功，将订单状态更新为已退款
            orderRepository.updatePayStatus(orderId, PayStatusEnum.REFUNDED, OrderStatusEnum.REFUND, null);
        } else if (refundStatus == RefundStatusEnum.CLOSE) {
            // 退款关闭，表示取消了退款
            orderRepository.updatePayStatus(orderId, PayStatusEnum.SUCCEED, null, null);
        } else if (refundStatus == RefundStatusEnum.REFUNDING) {
            orderRepository.updatePayStatus(orderId, PayStatusEnum.REFUNDING, null, null);
        }
        return true;
    }

    /**
     * 超时未支付，自动取消订单
     *
     * @param orderId 订单id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean orderCancel(Long orderId) {
        OrderEntity order = orderRepository.querySimpleOrderForUpdate(orderId);
        if (OrderTypeEnum.PT.getType().equals(order.getType())) {
            // 拼团单,除了取消订单之外，还得标记拼团Item为失败
            orderRepository.updateOrderStatus(orderId, OrderStatusEnum.CANCELED.getStatus());
            ptOrderService.ptOrderItemCanceled(orderId);
        } else {
            orderRepository.updateOrderStatus(orderId, OrderStatusEnum.CANCELED.getStatus());
        }
        return true;
    }
}
